import { Buffer } from "buffer";
import { GolombParse } from "./Golomb_Parse";

//ffmpeg
const AV_PIX_FMT_YUV420P: number = 0;
const AV_PIX_FMT_YUVJ420P: number = 12;
const AV_PIX_FMT_YUV422P: number = 4;
const AV_PIX_FMT_YUV444P: number = 5;
const AV_PIX_FMT_GRAY8: number = 8;
const EXTENDED_SAR:number = 255;//ffmpeg找到的值，意思未知

// let sps: Buffer = Buffer.from('Z00AKp2oHgCJ+WbgICAoAAAfQAAGGoQgAA==','base64');
// console.log(sps.toString('hex'));

class H265_Parse {
    private data: GolombParse;
    constructor(srcData: Buffer) {
        this.data = new GolombParse(srcData);
    }
    private map_pixel_format(chroma_format_idc: number,bit_depth:number): number {
        let pix_fmt: number = 0;
        switch (bit_depth) {
            case 8:
                if (chroma_format_idc == 0) pix_fmt = AV_PIX_FMT_GRAY8;
                if (chroma_format_idc == 1) pix_fmt = AV_PIX_FMT_YUV420P;
                if (chroma_format_idc == 2) pix_fmt = AV_PIX_FMT_YUV422P;
                if (chroma_format_idc == 3) pix_fmt = AV_PIX_FMT_YUV444P;
                break;
            // case 9:
            //     if (chroma_format_idc == 0) pix_fmt = AV_PIX_FMT_GRAY16;
            //     if (chroma_format_idc == 1) pix_fmt = AV_PIX_FMT_YUV420P9;
            //     if (chroma_format_idc == 2) pix_fmt = AV_PIX_FMT_YUV422P9;
            //     if (chroma_format_idc == 3) pix_fmt = AV_PIX_FMT_YUV444P9;
            //     break;
            // case 10:
            //     if (chroma_format_idc == 0) pix_fmt = AV_PIX_FMT_GRAY10;
            //     if (chroma_format_idc == 1) pix_fmt = AV_PIX_FMT_YUV420P10;
            //     if (chroma_format_idc == 2) pix_fmt = AV_PIX_FMT_YUV422P10;
            //     if (chroma_format_idc == 3) pix_fmt = AV_PIX_FMT_YUV444P10;
            //     break;
            // case 12:
            //     if (chroma_format_idc == 0) pix_fmt = AV_PIX_FMT_GRAY12;
            //     if (chroma_format_idc == 1) pix_fmt = AV_PIX_FMT_YUV420P12;
            //     if (chroma_format_idc == 2) pix_fmt = AV_PIX_FMT_YUV422P12;
            //     if (chroma_format_idc == 3) pix_fmt = AV_PIX_FMT_YUV444P12;
            //     break;
            default:
        }
        return pix_fmt;
    }
    private st_ref_pic_set(stRpsIdx: number, num_short_term_ref_pic_sets: number) {
        let inter_ref_pic_set_prediction_flag: number = 0;
        if (stRpsIdx != 0) {
            inter_ref_pic_set_prediction_flag = this.data.U(1);
        }
        if (inter_ref_pic_set_prediction_flag) {
            if (stRpsIdx == num_short_term_ref_pic_sets){
                let delta_idx_minus1: number = this.data.UE();
            }
            let delta_rps_sign: number = this.data.U(1);
            let abs_delta_rps_minus1: number = this.data.UE();
            console.log("不支持");
            // for (let j = 0; j <= NumDeltaPocs[RefRpsIdx]; j++) {
            //     let used_by_curr_pic_flag[j]: number = this.data.U(1);
            //     if (!used_by_curr_pic_flag[j])
            //         let use_delta_flag[j]: number = this.data.U(1);
            // }
        } else {
            let num_negative_pics: number = this.data.UE();
            let num_positive_pics: number = this.data.UE();
            let delta_poc_s0_minus1 = new Array<number>(num_negative_pics);
            let used_by_curr_pic_s0_flag = new Array<number>(num_negative_pics);
            for (let i = 0; i < num_negative_pics; i++) {
                delta_poc_s0_minus1[i] = this.data.UE();
                used_by_curr_pic_s0_flag[i] = this.data.U(1);
            }
            let delta_poc_s1_minus1 = new Array<number>(num_positive_pics);
            let used_by_curr_pic_s1_flag = new Array<number>(num_positive_pics);
            for (let i = 0; i < num_positive_pics; i++) {
                delta_poc_s1_minus1[i] = this.data.UE();
                used_by_curr_pic_s1_flag[i] = this.data.U(1);
            }
        }
    }
    private vui_parameters(ret: any):any{
        let aspect_ratio_info_present_flag = this.data.U(1);
        if (aspect_ratio_info_present_flag) {
            let aspect_ratio_idc = this.data.U(8);
            if (aspect_ratio_idc == EXTENDED_SAR) {
                let sar_width = this.data.U(16);
                let sar_height = this.data.U(16);
            }
        }
        let overscan_info_present_flag = this.data.U(1);
        if (overscan_info_present_flag){
            let overscan_appropriate_flag = this.data.U(1);
        }
        let video_signal_type_present_flag = this.data.U(1);
        if (video_signal_type_present_flag) {
            let video_format = this.data.U(3);
            let video_full_range_flag = this.data.U(1);
            let colour_description_present_flag = this.data.U(1);
            if (colour_description_present_flag) {
                let colour_primaries = this.data.U(8);
                let transfer_characteristics = this.data.U(8);
                let matrix_coeffs = this.data.U(8);
            }
            if (video_full_range_flag && ret.pix_fmt == AV_PIX_FMT_YUV420P)
                ret.pix_fmt = AV_PIX_FMT_YUVJ420P;
        }
        //下面不解析了，已经获得需要的数据了。
        return ret;
    }
    private PaeseSPS_profile_tier_level(profilePresentFlag:number,maxNumSubLayersMinus1:number):void{
        if (profilePresentFlag){
            let general_profile_space = this.data.U(2);
            let general_tier_flag = this.data.U(1);
            let general_profile_idc = this.data.U(5);
            let general_profile_compatibility_flag = new Array<number>(32);
            for (let j = 0; j < 32; j++) {
                general_profile_compatibility_flag[j] = this.data.U(1)
            }
            let general_progressive_source_flag = this.data.U(1);
            let general_interlaced_source_flag = this.data.U(1);
            let general_non_packed_constraint_flag = this.data.U(1);
            let general_frame_only_constraint_flag = this.data.U(1);
            if (general_profile_idc == 4 || general_profile_compatibility_flag[4] ||
                general_profile_idc == 5 || general_profile_compatibility_flag[5] ||
                general_profile_idc == 6 || general_profile_compatibility_flag[6] ||
                general_profile_idc == 7 || general_profile_compatibility_flag[7]) {
                let general_max_12bit_constraint_flag = this.data.U(1);
                let general_max_10bit_constraint_flag = this.data.U(1);
                let general_max_8bit_constraint_flag = this.data.U(1);
                let general_max_422chroma_constraint_flag = this.data.U(1);
                let general_max_420chroma_constraint_flag = this.data.U(1);
                let general_max_monochrome_constraint_flag = this.data.U(1);
                let general_intra_constraint_flag = this.data.U(1);
                let general_one_picture_only_constraint_flag = this.data.U(1);
                let general_lower_bit_rate_constraint_flag = this.data.U(1);
                let general_reserved_zero_34bits = this.data.U(34);
            } else {
                let general_reserved_zero_43bits = this.data.U(43);
            }
            if ((general_profile_idc >= 1 && general_profile_idc <= 5) ||
                general_profile_compatibility_flag[1] || general_profile_compatibility_flag[2] ||
                general_profile_compatibility_flag[3] || general_profile_compatibility_flag[4] ||
                general_profile_compatibility_flag[5]) {
                let general_inbld_flag = this.data.U(1);
            } else {
                let general_reserved_zero_bit = this.data.U(1);
            }
        }
        let general_level_idc = this.data.U(8);
        let sub_layer_profile_present_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_level_present_flag = new Array<number>(maxNumSubLayersMinus1);
        // let sub_layer_profile_compatibility_flag = new Array(Array<number>)(32)
        for (let i = 0; i < maxNumSubLayersMinus1; i++) {
            sub_layer_profile_present_flag[i] = this.data.U(1);
            sub_layer_level_present_flag[i] = this.data.U(1);
        }
        if (maxNumSubLayersMinus1 > 0){
            let reserved_zero_2bits = new Array<number>(maxNumSubLayersMinus1);
            for (let i = maxNumSubLayersMinus1; i < 8; i++)
                reserved_zero_2bits[i] = this.data.U(2);
        }
        let sub_layer_profile_space = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_tier_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_profile_idc = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_profile_compatibility_flag = new Array<Array<number>>(maxNumSubLayersMinus1);
        for (let i = 0; i < maxNumSubLayersMinus1; i++) {
            sub_layer_profile_compatibility_flag[i] = new Array<number>(32);
        }
        let sub_layer_progressive_source_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_interlaced_source_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_non_packed_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_frame_only_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_max_12bit_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_max_10bit_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_max_8bit_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_max_422chroma_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_max_420chroma_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_max_monochrome_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_intra_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_one_picture_only_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_lower_bit_rate_constraint_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_reserved_zero_34bits = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_reserved_zero_43bits = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_inbld_flag = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_reserved_zero_bit = new Array<number>(maxNumSubLayersMinus1);
        let sub_layer_level_idc = new Array<number>(maxNumSubLayersMinus1);
        for (let i = 0; i < maxNumSubLayersMinus1; i++) {
            if (sub_layer_profile_present_flag[i]) {
                sub_layer_profile_space[i] = this.data.U(2);
                sub_layer_tier_flag[i] = this.data.U(1);
                sub_layer_profile_idc[i] = this.data.U(5);
                for (let j = 0; j <32; j++) {
                    sub_layer_profile_compatibility_flag[i][j] = this.data.U(1);
                }
                sub_layer_progressive_source_flag[i] = this.data.U(1);
                sub_layer_interlaced_source_flag[i] = this.data.U(1);
                sub_layer_non_packed_constraint_flag[i] = this.data.U(1);
                sub_layer_frame_only_constraint_flag[i] = this.data.U(1);
                if (sub_layer_profile_idc[i] == 4 || sub_layer_profile_compatibility_flag[i][4] ||
                    sub_layer_profile_idc[i] == 5 || sub_layer_profile_compatibility_flag[i][5] ||
                    sub_layer_profile_idc[i] == 6 || sub_layer_profile_compatibility_flag[i][6] ||
                    sub_layer_profile_idc[i] == 7 || sub_layer_profile_compatibility_flag[i][7]) {
                    sub_layer_max_12bit_constraint_flag[i] = this.data.U(1);
                    sub_layer_max_10bit_constraint_flag[i] = this.data.U(1);
                    sub_layer_max_8bit_constraint_flag[i] = this.data.U(1);
                    sub_layer_max_422chroma_constraint_flag[i] = this.data.U(1);
                    sub_layer_max_420chroma_constraint_flag[i] = this.data.U(1);
                    sub_layer_max_monochrome_constraint_flag[i] = this.data.U(1);
                    sub_layer_intra_constraint_flag[i] = this.data.U(1);
                    sub_layer_one_picture_only_constraint_flag[i] = this.data.U(1);
                    sub_layer_lower_bit_rate_constraint_flag[i] = this.data.U(1);
                    sub_layer_reserved_zero_34bits[i] = this.data.U(1);
                } else {
                    sub_layer_reserved_zero_43bits[i] = this.data.U(1);
                }
                if ((sub_layer_profile_idc[i] >= 1 && sub_layer_profile_idc[i] <= 5) ||
                    sub_layer_profile_compatibility_flag[1] ||
                    sub_layer_profile_compatibility_flag[2] ||
                    sub_layer_profile_compatibility_flag[3] ||
                    sub_layer_profile_compatibility_flag[4] ||
                    sub_layer_profile_compatibility_flag[5]) {
                    sub_layer_inbld_flag[i] = this.data.U(1);
                } else {
                    sub_layer_reserved_zero_bit[i] = this.data.U(1);
                }
            }
            if(sub_layer_level_present_flag[i]){
                sub_layer_level_idc[i] = this.data.U(8);
            }
        }
    }
    public PaeseSPS(): any {
        let ret: any = { pix_fmt: AV_PIX_FMT_YUV420P };
        let forbidden_zero_bit: number = this.data.U(1);
        let nal_unit_type: number = this.data.U(6);
        let nuh_layer_id: number = this.data.U(6);
        let nuh_temporal_id_plus1: number = this.data.U(3);
        if (nal_unit_type == 33) {
            let sps_video_parameter_set_id: number = this.data.U(4);
            let sps_max_sub_layers_minus1 = this.data.U(3);
            let sps_temporal_id_nesting_flag: number = this.data.U(1);
            this.data.U(24);//TODO 什么鬼，标准上没有
            this.PaeseSPS_profile_tier_level(1, sps_max_sub_layers_minus1);
            let sps_seq_parameter_set_id: number = this.data.UE();
            let chroma_format_idc: number = this.data.UE();
            let separate_colour_plane_flag: number = 0;
            if (chroma_format_idc == 3) {
                separate_colour_plane_flag = this.data.U(1);
            }
            let pic_width_in_luma_samples: number = this.data.UE();
            let pic_height_in_luma_samples: number = this.data.UE();
            let conformance_window_flag: number = this.data.U(1);
            let conf_win_left_offset: number = 0;
            let conf_win_right_offset: number = 0;
            let conf_win_top_offset: number = 0;
            let conf_win_bottom_offset: number = 0;
            if (conformance_window_flag) {
                conf_win_left_offset = this.data.UE();
                conf_win_right_offset = this.data.UE();
                conf_win_top_offset = this.data.UE();
                conf_win_bottom_offset = this.data.UE();
            }
            let bit_depth_luma_minus8: number = this.data.UE();
            let bit_depth_chroma_minus8: number = this.data.UE();
            ret.pix_fmt = this.map_pixel_format(chroma_format_idc, bit_depth_luma_minus8);

            // 宽高计算公式
            ret.width = pic_width_in_luma_samples;
            ret.height = pic_height_in_luma_samples;
            let sub_width_c = ((1 == chroma_format_idc) || (2 == chroma_format_idc)) && (0 == separate_colour_plane_flag) ? 2 : 1;
            let sub_height_c = (1 == chroma_format_idc) && (0 == separate_colour_plane_flag) ? 2 : 1;
            ret.width -= (sub_width_c * conf_win_right_offset + sub_width_c * conf_win_left_offset);
            ret.height -= (sub_height_c * conf_win_bottom_offset + sub_height_c * conf_win_top_offset);

            let log2_max_pic_order_cnt_lsb_minus4: number = this.data.UE();
            let sps_sub_layer_ordering_info_present_flag: number = this.data.U(1);
            let sps_max_dec_pic_buffering_minus1 = new Array<number>(sps_max_sub_layers_minus1+1);
            let sps_max_num_reorder_pics = new Array<number>(sps_max_sub_layers_minus1+1);
            let sps_max_latency_increase_plus1 = new Array<number>(sps_max_sub_layers_minus1+1);
            for (let i = (sps_sub_layer_ordering_info_present_flag ? 0 : sps_max_sub_layers_minus1);i <= sps_max_sub_layers_minus1; i++) {
                sps_max_dec_pic_buffering_minus1[i] = this.data.UE();
                sps_max_num_reorder_pics[i] = this.data.UE();
                sps_max_latency_increase_plus1[i] = this.data.UE();
            }
            let log2_min_luma_coding_block_size_minus3: number = this.data.UE();
            let log2_diff_max_min_luma_coding_block_size: number = this.data.UE();
            let log2_min_luma_transform_block_size_minus2: number = this.data.UE();
            let log2_diff_max_min_luma_transform_block_size: number = this.data.UE();
            let max_transform_hierarchy_depth_inter: number = this.data.UE();
            let max_transform_hierarchy_depth_intra: number = this.data.UE();
            let scaling_list_enabled_flag: number = this.data.U(1);
            if (scaling_list_enabled_flag) {
                let sps_scaling_list_data_present_flag: number = this.data.U(1);
                if (sps_scaling_list_data_present_flag) {
                    // scaling_list_data() //不支持
                    console.log("不支持scaling_list_data()");
                    return ret;
                }
            }
            let amp_enabled_flag: number = this.data.U(1);
            let sample_adaptive_offset_enabled_flag: number = this.data.U(1);
            let pcm_enabled_flag: number = this.data.U(1);
            if (pcm_enabled_flag) {
                let pcm_sample_bit_depth_luma_minus1: number = this.data.U(4);
                let pcm_sample_bit_depth_chroma_minus1: number = this.data.U(4);
                let log2_min_pcm_luma_coding_block_size_minus3: number = this.data.UE();
                let log2_diff_max_min_pcm_luma_coding_block_size: number = this.data.UE();
                let pcm_loop_filter_disabled_flag: number = this.data.U(1);
            }
            let num_short_term_ref_pic_sets: number = this.data.UE();
            for (let i = 0; i < num_short_term_ref_pic_sets; i++){
                this.st_ref_pic_set(i, num_short_term_ref_pic_sets)
            }
            let long_term_ref_pics_present_flag: number = this.data.U(1);
            if (long_term_ref_pics_present_flag) {
                let num_long_term_ref_pics_sps: number = this.data.UE();
                let lt_ref_pic_poc_lsb_sps = new Array<number>(num_long_term_ref_pics_sps);
                let used_by_curr_pic_lt_sps_flag = new Array<number>(num_long_term_ref_pics_sps);
                for (let i = 0; i < num_long_term_ref_pics_sps; i++) {
                    lt_ref_pic_poc_lsb_sps[i] = this.data.UE();
                    used_by_curr_pic_lt_sps_flag[i] = this.data.U(1);
                }
            }
            let sps_temporal_mvp_enabled_flag: number = this.data.U(1);
            let strong_intra_smoothing_enabled_flag: number = this.data.U(1);
            let vui_parameters_present_flag: number = this.data.U(1);
            if (vui_parameters_present_flag){
                ret = this.vui_parameters(ret);
            }
            let sps_extension_present_flag: number = this.data.U(1);
            //TODO 剩下的数据忽略，实在不想搞了
            return ret;
        } else {
            return ret;
        }
    }
}

export function getH265SPSInfo(sps: Buffer): any {
    let parse = new H265_Parse(sps);
    let info = parse.PaeseSPS();
    return info;
}


export const H265CodecID: number = 174;